package com.hspedu.seckill.controller;

import cn.hutool.json.JSONUtil;
import com.hspedu.seckill.config.AccessLimit;
import com.hspedu.seckill.pojo.SeckillMessage;
import com.hspedu.seckill.pojo.SeckillOrder;
import com.hspedu.seckill.pojo.User;
import com.hspedu.seckill.rabbitmq.MQSenderMessage;
import com.hspedu.seckill.service.GoodsService;
import com.hspedu.seckill.service.OrderService;
import com.hspedu.seckill.service.SeckillOrderService;
import com.hspedu.seckill.util.UUIDUtil;
import com.hspedu.seckill.vo.GoodsVo;
import com.hspedu.seckill.vo.RespBean;
import com.hspedu.seckill.vo.RespBeanEnum;
import com.ramostear.captcha.HappyCaptcha;
import com.ramostear.captcha.common.Fonts;
import com.ramostear.captcha.support.CaptchaStyle;
import com.ramostear.captcha.support.CaptchaType;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Controller
@RequestMapping("seckill")
public class SeckillController implements InitializingBean {

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private OrderService orderService;

    @Resource
    private GoodsService goodsService;

    //定义map-记录秒杀商品是否还有库存
    private Map<Long, Boolean> mt = new HashMap<>();

    @Resource
    private MQSenderMessage mqSenderMessage;

    @Resource
    private SeckillOrderService seckillOrderService;

    @Resource
    private RedisScript redisScript;

    //@RequestMapping("/{path}/doSeckill")
    ////@RequestMapping("/doSeckill")
    //@ResponseBody
    //public RespBean doSeckill(@PathVariable String path, User user, Long goodsId, Model model) {
    //    //用户未登录
    //    if (null == user) {
    //        //model.addAttribute("errmsg",RespBeanEnum.SESSION_ERROR.getMessage());
    //        //return "seckillFail";
    //        return RespBean.error(RespBeanEnum.SESSION_ERROR);
    //    }
    //    //goodsId为空
    //    if (null == goodsId) {
    //        //model.addAttribute("errmsg",RespBeanEnum.SESSION_ERROR.getMessage());
    //        //return "seckillFail";
    //        return RespBean.error(RespBeanEnum.SESSION_ERROR);
    //    }
    //
    //    //没有秒杀地址
    //    if (!StringUtils.hasText(path)) {
    //        //model.addAttribute("errmsg",RespBeanEnum.REQUEST_ILLEGAL.getMessage());
    //        //return "seckillFail";
    //        return RespBean.error(RespBeanEnum.REQUEST_ILLEGAL);
    //    }
    //
    //
    //    //携带的秒杀地址跟redis中的秒杀地址不一样
    //    if (!orderService.checkPath(user, goodsId, path)) {
    //        //model.addAttribute("errmsg",RespBeanEnum.REQUEST_ILLEGAL.getMessage());
    //        //return "seckillFail";
    //        return RespBean.error(RespBeanEnum.REQUEST_ILLEGAL);
    //    }
    //
    //    //该商品每人限购一件
    //    SeckillOrder seckillOrder = (SeckillOrder) redisTemplate.opsForValue().get("order:" + user.getId() + ":" + goodsId);
    //    if (null != seckillOrder) {
    //        //model.addAttribute("errmsg",RespBeanEnum.REPEAT_ERROR.getMessage());
    //        //return "seckillFail";
    //        return RespBean.error(RespBeanEnum.REPEAT_ERROR);
    //    }
    //
    //
    //    if (!mt.get(goodsId)) {
    //        //返回商品库存不足
    //        //model.addAttribute("errmsg",RespBeanEnum.ENTRY_STOCK.getMessage());
    //        //return "seckillFail";
    //        return RespBean.error(RespBeanEnum.ENTRY_STOCK);
    //    }
    //
    //    //1 获取锁，setnx
    //    //得到一个 uuid 值，作为锁的值
    //    String uuid = UUIDUtil.uuid();
    //    Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3, TimeUnit.SECONDS);
    //    //2 获取锁成功、查询 num 的值
    //    if (lock) {
    //
    //        //从redis将库存减1
    //        Long increment = redisTemplate.opsForValue().decrement("seckillGoodsStock:" + goodsId);
    //        //若redis库存小于0
    //        if (increment < 0) {
    //            mt.put(goodsId, false);
    //            //将redis库存还原到0
    //            redisTemplate.opsForValue().increment("seckillGoodsStock:" + goodsId);
    //
    //            //2.4 释放锁，del
    //            redisTemplate.execute(redisScript, Arrays.asList("lock"), uuid);
    //            //返回商品库存不足
    //            return RespBean.error(RespBeanEnum.ENTRY_STOCK);
    //        }
    //
    //        //2.4 释放锁，del
    //        redisTemplate.execute(redisScript, Arrays.asList("lock"), uuid);
    //    } else {
    //        //秒杀失败
    //        return RespBean.error(RespBeanEnum.SECKILL_ERROR);
    //
    //    }
    //
    //
    //    GoodsVo goodsVo = goodsService.findGoodsVoByGoodsId(goodsId);
    //
    //    //Order order = orderService.seckill(user, goodsVo);
    //    //if (null == order){
    //    //    model.addAttribute("errmsg",RespBeanEnum.SECKILL_ERROR.getMessage());
    //    //    return "seckillFail";
    //    //}
    //
    //    //构建SeckillMessage
    //    SeckillMessage seckillMessage = new SeckillMessage();
    //    seckillMessage.setUser(user);
    //    seckillMessage.setGoodsVo(goodsVo);
    //
    //    //将SeckillMessage转成json字符串
    //    String seckillMessageStr = JSONUtil.toJsonStr(seckillMessage);
    //    //调用消息生产者完成异步秒杀
    //    mqSenderMessage.sender(seckillMessageStr);
    //
    //
    //    //model.addAttribute("errmsg",RespBeanEnum.SEC_KILL_WAIT.getMessage());
    //    //model.addAttribute("goodsId",goodsId);
    //
    //    //return "seckillFail";
    //    return RespBean.error(RespBeanEnum.SEC_KILL_WAIT);
    //}


    @RequestMapping("/doSeckill")
    @ResponseBody
    public RespBean doSeckill(User user, Long goodsId) {
        //用户未登录
        if (null == user) {
            //model.addAttribute("errmsg",RespBeanEnum.SESSION_ERROR.getMessage());
            //return "seckillFail";
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }
        //goodsId为空
        if (null == goodsId) {
            //model.addAttribute("errmsg",RespBeanEnum.SESSION_ERROR.getMessage());
            //return "seckillFail";
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }


        //该商品每人限购一件
        SeckillOrder seckillOrder = (SeckillOrder) redisTemplate.opsForValue().get("order:" + user.getId() + ":" + goodsId);
        if (null != seckillOrder) {
            //model.addAttribute("errmsg",RespBeanEnum.REPEAT_ERROR.getMessage());
            //return "seckillFail";
            return RespBean.error(RespBeanEnum.REPEAT_ERROR);
        }


        if (!mt.get(goodsId)) {
            //返回商品库存不足
            //model.addAttribute("errmsg",RespBeanEnum.ENTRY_STOCK.getMessage());
            //return "seckillFail";
            return RespBean.error(RespBeanEnum.ENTRY_STOCK);
        }

        //1 获取锁，setnx
        //得到一个 uuid 值，作为锁的值
        String uuid = UUIDUtil.uuid();
        Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 3, TimeUnit.SECONDS);
        //2 获取锁成功、查询 num 的值
        if (lock) {

            //从redis将库存减1
            Long increment = redisTemplate.opsForValue().decrement("seckillGoodsStock:" + goodsId);
            //若redis库存小于0
            if (increment < 0) {
                mt.put(goodsId, false);
                //将redis库存还原到0
                redisTemplate.opsForValue().increment("seckillGoodsStock:" + goodsId);

                //2.4 释放锁，del
                redisTemplate.execute(redisScript, Arrays.asList("lock"), uuid);
                //返回商品库存不足
                return RespBean.error(RespBeanEnum.ENTRY_STOCK);
            }

            //2.4 释放锁，del
            redisTemplate.execute(redisScript, Arrays.asList("lock"), uuid);
        } else {
            //秒杀失败
            return RespBean.error(RespBeanEnum.SECKILL_ERROR);

        }


        GoodsVo goodsVo = goodsService.findGoodsVoByGoodsId(goodsId);

        //Order order = orderService.seckill(user, goodsVo);
        //if (null == order){
        //    model.addAttribute("errmsg",RespBeanEnum.SECKILL_ERROR.getMessage());
        //    return "seckillFail";
        //}

        //构建SeckillMessage
        SeckillMessage seckillMessage = new SeckillMessage();
        seckillMessage.setUser(user);
        seckillMessage.setGoodsVo(goodsVo);

        //将SeckillMessage转成json字符串
        String seckillMessageStr = JSONUtil.toJsonStr(seckillMessage);
        //调用消息生产者完成异步秒杀
        mqSenderMessage.sender(seckillMessageStr);


        //model.addAttribute("errmsg",RespBeanEnum.SEC_KILL_WAIT.getMessage());
        //model.addAttribute("goodsId",goodsId);

        //return "seckillFail";
        return RespBean.error(RespBeanEnum.SEC_KILL_WAIT);
    }

    //初始化商品库存在redis
    @Override
    public void afterPropertiesSet() throws Exception {
        List<GoodsVo> goodsVoList = goodsService.findGoodsVo();
        if (!goodsVoList.isEmpty()) {
            for (GoodsVo goodsVo : goodsVoList) {
                mt.put(goodsVo.getId(), true);
                redisTemplate.opsForValue().set("seckillGoodsStock:" + goodsVo.getId(), goodsVo.getStockCount());
            }
        }

    }

    //获取秒杀结果
    @RequestMapping("/getSecKillResult")
    @ResponseBody
    public RespBean getSecKillResult(User user, Long goodsId) {
        if (null == user) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }

        if (null == goodsId) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }

        Integer secKillResult = (Integer) redisTemplate.opsForValue().get("secKillResult:" + user.getId() + ":" + goodsId);

        //如果秒杀结果为空，说明秒杀排队中
        if (null == secKillResult) {
            secKillResult = 0;
        }

        //秒杀状态：0排队中，-1秒杀失败，orderId秒杀成功


        return RespBean.success(secKillResult);
    }


    /**
     * 获取秒杀地址
     */
    @AccessLimit(seconds = 5, count = 5, needLogin = true)
    @RequestMapping("/path")
    @ResponseBody
    public RespBean getSeckillPath(User user, Long goodsId, String captcha) {
        if (null == user) {
            return RespBean.error(RespBeanEnum.SESSION_ERROR);
        }

        //获取请求的uri
        // String uri = request.getRequestURI();
        // //获取redis该用户方法这个请求地址的次数
        // Integer count = (Integer)redisTemplate.opsForValue().get(uri + ":" + user.getId());
        //
        //
        // //如果没有访问过就初始化redis该用户方法这个请求地址的次数为0，过期时间设置为5s
        // if (null == count){
        //     redisTemplate.opsForValue().set(uri + ":" + user.getId(),0,5,TimeUnit.SECONDS);
        // }else if (count > 5){//如果5秒内该用户的访问次数大于5就提示频繁访问
        //     return RespBean.error(RespBeanEnum.ACCESS_LIMIT_REACHED);
        // }else {
        //     //将redis该用户方法这个请求地址的次数加1
        //     redisTemplate.opsForValue().increment(uri + ":" + user.getId());
        // }
        //
        // if (null == goodsId) {
        //     return RespBean.error(RespBeanEnum.SESSION_ERROR);
        // }
        //
        // if (!StringUtils.hasText(captcha)){
        //     return RespBean.error(RespBeanEnum.CAPTCHA_ERROR);
        // }


        //校验验证码错误
        boolean checkCaptcha = orderService.checkCaptcha(user, goodsId, captcha);
        if (!checkCaptcha) {
            return RespBean.error(RespBeanEnum.CAPTCHA_ERROR);
        }


        return RespBean.success(orderService.createPath(user, goodsId));


    }


    /**
     * 获取验证码，并存放到redis中
     */
    @GetMapping("/captcha")
    public void captcha(HttpServletRequest request, HttpServletResponse response, User user, Long goodsId) {
        HappyCaptcha.require(request, response)
                .style(CaptchaStyle.ANIM)            //设置展现样式为动画
                .type(CaptchaType.NUMBER)            //设置验证码内容为数字
                .length(6)                            //设置字符长度为6
                .width(220)                            //设置动画宽度为220
                .height(80)                            //设置动画高度为80
                .font(Fonts.getInstance().zhFont())    //设置汉字的字体
                .build().finish();                //生成并输出验证码

        //获取session中存放的验证码
        String captcha = (String) request.getSession().getAttribute("happy-captcha");
        if (StringUtils.hasText(captcha)) {
            //将验证码存放到redis中，并设置有效时间60秒
            redisTemplate.opsForValue().set("captcha:" + user.getId() + ":" + goodsId, captcha, 60, TimeUnit.SECONDS);
        }

    }
}
